package com.annis.myviewpager

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.Scroller
import android.widget.Toast
import androidx.core.view.children

/**
 * @author Lee
 * @date 2019/3/28 11:12
 * @Description
 * function
 * 1.滑动     切换(控制可超出30%宽度)
 * 2.点击左右 切换(达到边界是 超出10%宽度 的动画)
 *
 *
 * 状态
 * 1.滑动   2.静止
 * 事件
 * 1.点击(I.静止点击  II.滚动点击)   2.拖拽
 *
 */
class MyViewPager : ViewGroup {
    private val mDragDistance = 10

    interface PageChanger {
        /**
         * 页面改变的回调
         */
        fun onPageChanged(page: Int)
    }

    constructor(context: Context) : super(context) {
        initView(context)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        initView(context)
    }

    var mPageChanger: PageChanger? = null

    /**
     * 界面取值
     */
    private var maxWidth: Int = 0
    private var spillScrollWidth: Int = 0//允许滑动溢出范围
    private var spillShowWidth: Int = 0//允许提示溢出范围
    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        Log.w("MyViewpager", "onLayout  changed:$changed  l:$l  t:$t  r:$r  b:$b")
        Log.w("MyViewpager", "onLayout  screen width:$width  height:$height")
        maxWidth = (childCount - 1) * width
        spillScrollWidth = (width * 0.3).toInt()
        spillShowWidth = (width * 0.1).toInt()

        for (i in 0 until childCount) {
            getChildAt(i).layout(i * width, 0, (i + 1) * width, height)
        }
    }

    /**
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     * 1.测量的时候测量多次
     * 2.widthMeasureSpec父层视图给当前视图的宽和模式
     *      系统的onMeasure()中所干的事：
     *        1、根据 widthMeasureSpec 求得宽度width，和父view给的模式
     *        2、根据自身的宽度width 和自身的padding 值，相减，求得子view可以拥有的宽度newWidth
     *        3、根据 newWidth 和模式求得一个新的MeasureSpec值:
     *           MeasureSpec.makeMeasureSpec(newSize, newmode);
     *        4、用新的MeasureSpec来计算子view
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val a = MeasureSpec.AT_MOST
        val b = MeasureSpec.EXACTLY
        val modeWidth = MeasureSpec.getMode(widthMeasureSpec)
        val sizeWidth = MeasureSpec.getSize(widthMeasureSpec)

        val modeHeight = MeasureSpec.getMode(heightMeasureSpec)
        val sizeHeight = MeasureSpec.getSize(heightMeasureSpec)
        //还可以重新组装
        val spec = MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth)

        Log.w("MyViewpager", "onMeasure: width:$widthMeasureSpec    $modeWidth-$sizeWidth")
        Log.w("MyViewpager", "onMeasure: height:$heightMeasureSpec   $modeHeight-$sizeHeight")
        children.iterator().forEach {
            measureChild(it,widthMeasureSpec,heightMeasureSpec)
//            it.measure(widthMeasureSpec, heightMeasureSpec)
        }
    }
    private lateinit var scroller: Scroller
    /**
     * 子View 有时间相应时onScroll() ->distanceX 的值会异常,所以 取消使用
     */
    //    private lateinit var gestureDetector: GestureDetector
    private fun initView(context: Context) {
        Log.w("MyViewpager", "initView")
        scroller = Scroller(context)
//        gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
//            override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
//                var dX = distanceX
//                val toX = scrollX + distanceX
//                if (toX < -spillScrollWidth) {
//                    dX = 0f
//                } else if (toX > maxWidth + spillScrollWidth) {
//                    dX = 0f
//                }
//                //gestureDetector
//                scrollBy(dX.toInt(), 0)
//                Log.w("MyViewpager", "GestureDetector  onScroll  dX:$dX   --   toX:$toX")
//                return true
//            }
//        })
    }

    private var downX = 0f
    private var downY = 0f
    /**
     * 事件拦截控制
     */
    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        var intercept = false
        when (ev?.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.w("MyViewpager", "onInterceptTouchEvent  ACTION_DOWN intercept:$intercept  ev.rawX:${ev.rawX}")
                actionDown(ev)
            }
            MotionEvent.ACTION_MOVE -> {
                val distanceX = Math.abs(downX - ev.rawX)
                val distanceY = Math.abs(downY - ev.rawY)
                if (distanceX > distanceY && distanceX > mDragDistance) {
                    intercept = true
                }
                Log.w("MyViewpager", "onInterceptTouchEvent  ACTION_MOVE intercept:$intercept   ev.rawX:${ev.rawX}")
            }
            MotionEvent.ACTION_UP -> {
                Log.w("MyViewpager", "onInterceptTouchEvent  ACTION_UP intercept:$intercept   ev.rawX:${ev.rawX}")
            }
        }
//        if (intercept)//只有拦截了的事件才处理
//            gestureDetector.onTouchEvent(ev)
        return intercept
    }

    /**
     * 事件状态
     */
    private var isDrag = false//是否是拖拽事件
    private var showOut = false//是否显示视图外内容
    private var sliding = false//是否在滑动
    private var slidingChecked = false//是否在滑动 时有点击
    private var toutchEvent = MotionEvent.ACTION_UP
    /**
     * 页面状态
     */
    private var currentIndex = 0
    private var startX: Float = 0f
    private var lastX: Float = 0f
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.w("MyViewpager", "onTouchEvent  ACTION_DOWN isDrag:$isDrag")
                toutchEvent = MotionEvent.ACTION_DOWN
                actionDown(event)
            }
            MotionEvent.ACTION_MOVE -> {
                toutchEvent = MotionEvent.ACTION_MOVE
                if (Math.abs(startX - event.rawX) > mDragDistance) {
                    isDrag = true
                }

                var dX = event.rawX - lastX
                val toX = scrollX + dX
                if (toX < -spillScrollWidth) {
                    dX = 0f
                } else if (toX > maxWidth + spillScrollWidth) {
                    dX = 0f
                }
                lastX = event.rawX
                scrollBy(-dX.toInt(), 0)
                Log.w("MyViewpager", "onTouchEvent  ACTION_MOVE  isDrag:$isDrag   dX:$dX   --   toX:$toX")
            }
            MotionEvent.ACTION_UP -> {
                Log.w("MyViewpager", "onTouchEvent  ACTION_UP isDrag:$isDrag")
                toutchEvent = MotionEvent.ACTION_UP
                actionUp(event)
            }
        }
        return true
    }

    private fun actionDown(event: MotionEvent) {
        //状态重置
        //事件处理
        startX = event.rawX
        showOut = false
        isDrag = false
        //事件拦截
        downX = event.rawX
        lastX = event.rawX
        downY = event.rawY
    }

    private fun actionUp(event: MotionEvent?) {

        if (event == null)
            return
        //1.计算出将到达的页面
        if (!isDrag) { //点击事件  rawX
            val right = event.rawX > (width / 2)
            if (right) {//右
                //已经在边界   && scrollX >= maxWidth       && scrollX <= 0
                if ((currentIndex == childCount - 1)) {
                    showOut = true
                }
                currentIndex++
            } else {//左
                if (currentIndex == 0) {
                    showOut = true
                }
                currentIndex--
            }
        } else {  //处理拖拽事件  x
            if (event.rawX - startX > (width / 2)) {
                currentIndex--
            }
            if (startX - event.rawX > (width / 2)) {
                currentIndex++
            }
        }
        scrollToPage(currentIndex)
    }

    fun scrollToPage(pageTo: Int) {
        //2.防止 角标 溢出
        var pageToTemp = pageTo
        if (pageToTemp < 0) pageToTemp = 0
        if (pageToTemp >= childCount) pageToTemp = childCount - 1
        currentIndex = pageToTemp
        //3.总距离计算出来
        val distanceX = pageToTemp * width - scrollX
        //4.执行滚动
        if (!showOut) {
            scroller.startScroll(scrollX, scrollY, distanceX, 0, Math.abs(distanceX))
            invalidate()//强制绘制;//onDraw();computeScroll();
        } else {
            if (!sliding) {
                pushOut()
            } else {
                //正在滑动,不响应本次点击
                //保存至滑动结束
                slidingChecked = true
            }
        }
    }

    override fun computeScroll() {
        if (scroller.computeScrollOffset()) {//滑动中
            Log.w("MyViewpager", "computeScroll  滑动中  isDrag:$isDrag    sliding:$sliding ")
            sliding = true
            //得到移动这个一小段对应的坐标
            val currX = scroller.currX
            scrollTo(currX, 0)
            invalidate()
        } else {//不滑动了
            Log.w("MyViewpager", "computeScroll  不滑动了  isDrag:$isDrag    sliding:$sliding ")
            sliding = false
            mPageChanger?.apply {
                this.onPageChanged(currentIndex)
            }
            if (slidingChecked) {
                //消费之后重置
                slidingChecked = false
                pushOut()
                return
            }
            //归位
            if (showOut) {
                //消费之后重置
                showOut = false
                pullOut()
            } else {
            }
        }
    }

    /**
     * 弹出边界
     * ##需要防止一直点击一直移动
     */
    private fun pushOut() {
        if (scrollX < 0 || scrollX > maxWidth) { //已经推出
            if (!sliding) {//没有滑动
                pullOut()
            }
            return
        }
        scroller.startScroll(
            scrollX, scrollY, when (currentIndex) {
                0 -> -spillShowWidth
                else -> spillShowWidth
            }, 0, spillShowWidth * 2
        )
        invalidate()//强制绘制;//onDraw();computeScroll();
    }

    /**
     *  收回边界
     */
    private fun pullOut() {
        if (scrollX < 0) {
            scroller.startScroll(scrollX, scrollY, -scrollX, 0, spillShowWidth * 2)
        } else if (scrollX > maxWidth) {
            scroller.startScroll(scrollX, scrollY, maxWidth - scrollX, 0, spillShowWidth * 2)
        }
        invalidate()//强制绘制;//onDraw();computeScroll();
    }
}